use std::path::PathBuf;
use rusqlite::{Connection, params, OptionalExtension};
use serde::{Serialize, Deserialize};
use std::collections::HashMap;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModelConfig {
    pub base_url: String,
    pub api_key: String,
    pub model: String,
    #[serde(default)]
    pub headers: HashMap<String, String>,
    #[serde(default)]
    pub default_temperature: Option<f32>,
    #[serde(default)]
    pub default_max_tokens: Option<u32>,
}

pub fn open_db(path: &PathBuf) -> rusqlite::Result<Connection> {
    let conn = Connection::open(path)?;
    conn.pragma_update(None, "journal_mode", &"WAL")?;
    conn.execute(
        "CREATE TABLE IF NOT EXISTS model_config (
            key TEXT PRIMARY KEY,
            base_url TEXT NOT NULL,
            api_key TEXT NOT NULL,
            model TEXT NOT NULL,
            headers TEXT NOT NULL,
            default_temperature REAL NULL,
            default_max_tokens INTEGER NULL
        )",
        [],
    )?;
    conn.execute(
        "CREATE TABLE IF NOT EXISTS app_settings (
            key TEXT PRIMARY KEY,
            value TEXT NOT NULL
        )",
        [],
    )?;
    Ok(conn)
}

pub fn upsert_config(db_path: &PathBuf, key: &str, config: &ModelConfig) -> rusqlite::Result<()> {
    let conn = open_db(db_path)?;
    let headers_json = serde_json::to_string(&config.headers).unwrap_or("{}".into());
    conn.execute(
        "INSERT INTO model_config (key, base_url, api_key, model, headers, default_temperature, default_max_tokens)
         VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)
         ON CONFLICT(key) DO UPDATE SET
           base_url=excluded.base_url,
           api_key=excluded.api_key,
           model=excluded.model,
           headers=excluded.headers,
           default_temperature=excluded.default_temperature,
           default_max_tokens=excluded.default_max_tokens",
        params![
            key,
            config.base_url,
            config.api_key,
            config.model,
            headers_json,
            config.default_temperature,
            config.default_max_tokens
        ],
    )?;
    Ok(())
}

pub fn load_config(db_path: &PathBuf, key: &str) -> rusqlite::Result<ModelConfig> {
    let conn = open_db(db_path)?;
    let mut stmt = conn.prepare(
        "SELECT base_url, api_key, model, headers, default_temperature, default_max_tokens FROM model_config WHERE key=?1",
    )?;
    let res = stmt
        .query_row(params![key], |row| {
            let headers_str: String = row.get(3)?;
            let headers_map: HashMap<String, String> = serde_json::from_str(&headers_str).unwrap_or_default();
            Ok(ModelConfig {
                base_url: row.get(0)?,
                api_key: row.get(1)?,
                model: row.get(2)?,
                headers: headers_map,
                default_temperature: row.get::<_, Option<f64>>(4)?.map(|v| v as f32),
                default_max_tokens: row.get(5)?,
            })
        })
        .optional()?;
    res.ok_or_else(|| rusqlite::Error::QueryReturnedNoRows)
}

pub fn list_keys(db_path: &PathBuf) -> rusqlite::Result<Vec<String>> {
    let conn = open_db(db_path)?;
    let mut stmt = conn.prepare("SELECT key FROM model_config ORDER BY key")?;
    let rows = stmt.query_map([], |row| row.get::<_, String>(0))?;
    let mut keys = Vec::new();
    for k in rows { keys.push(k?); }
    Ok(keys)
}

pub fn delete_config(db_path: &PathBuf, key: &str) -> rusqlite::Result<()> {
    let conn = open_db(db_path)?;
    conn.execute("DELETE FROM model_config WHERE key=?1", params![key])?;
    Ok(())
}

// ------------- app settings (key-value)
pub fn set_setting(db_path: &PathBuf, key: &str, value: &str) -> rusqlite::Result<()> {
    let conn = open_db(db_path)?;
    conn.execute(
        "INSERT INTO app_settings (key, value) VALUES (?1, ?2)
         ON CONFLICT(key) DO UPDATE SET value=excluded.value",
        params![key, value],
    )?;
    Ok(())
}

pub fn get_setting(db_path: &PathBuf, key: &str) -> rusqlite::Result<Option<String>> {
    let conn = open_db(db_path)?;
    let mut stmt = conn.prepare("SELECT value FROM app_settings WHERE key=?1")?;
    let res = stmt.query_row(params![key], |row| row.get::<_, String>(0)).optional()?;
    Ok(res)
}


